/******************************************************************************* * Copyright (c) 2012-2015 Codenvy, S.A. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Codenvy, S.A. - initial API and implementation *******************************************************************************/ package org.eclipse.che.ide.ant.tools; import org.eclipse.che.api.core.util.CommandLine; import org.eclipse.che.api.core.util.LineConsumer; import org.eclipse.che.api.core.util.ProcessUtil; import org.eclipse.che.api.vfs.server.VirtualFile; import org.eclipse.che.vfs.impl.fs.VirtualFileImpl; import org.apache.tools.ant.Project; import org.apache.tools.ant.helper.ProjectHelper2; import java.io.FileFilter; import java.io.IOException; import java.io.Writer; import java.nio.charset.Charset; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; import java.util.HashMap; import java.util.Hashtable; import java.util.List; import java.util.Map; /** @author andrew00x */ // TODO: avoid usage org.apache.tools.ant.Project for representation Ant project. public class AntUtils { private static final Path BUILD_FILE_PATH = Paths.get(System.getProperty("java.io.tmpdir"), "codenvy_ant_properties.xml"); private static final String BUILD_FILE_CONTENT = "<project name=\"ant_properties\" default=\"get_properties\">\n" + " <target name=\"get_properties\">\n" + " <echo>Ant version: ${ant.version}</echo>\n" + " <echo>Ant home: ${ant.home}</echo>\n" + " <echo>Java version: ${java.version}, vendor: ${java.vendor}</echo>\n" + " <echo>Java home: ${java.home}</echo>\n" + " <echo>OS name: \"${os.name}\", version: \"${os.version}\", " + "arch: \"${os.arch}\"</echo>\n" + " </target>\n" + "</project>\n"; /** Not instantiable. */ private AntUtils() { } public static String getAntExecCommand() { final java.io.File antHome = getAntHome(); if (antHome != null) { final String ant = "bin" + java.io.File.separatorChar + "ant"; return new java.io.File(antHome, ant).getAbsolutePath(); // If ant home directory set use it } else { return "ant"; // otherwise 'ant' should be in PATH variable } } public static java.io.File getAntHome() { final String antHomeEnv = System.getenv("ANT_HOME"); if (antHomeEnv == null) { return null; } java.io.File antHome = new java.io.File(antHomeEnv); return antHome.exists() ? antHome : null; } private static java.io.File getJavaHome() { final String javaHomeEnv = System.getenv("JAVA_HOME"); if (javaHomeEnv == null) { return null; } java.io.File javaHome = new java.io.File(javaHomeEnv); return javaHome.exists() ? javaHome : null; } private static java.io.File getJavaHome2() { String javaHomeSys = System.getProperty("java.home"); if (javaHomeSys == null) { return null; } java.io.File javaHome = new java.io.File(javaHomeSys); if (!javaHome.exists()) { return null; } final String toolsJar = "lib" + java.io.File.separatorChar + "tools.jar"; if (new java.io.File(javaHome, toolsJar).exists()) { return javaHome; } if (javaHomeSys.endsWith("jre")) { javaHomeSys = javaHomeSys.substring(0, javaHomeSys.length() - 4); // remove "/jre" } javaHome = new java.io.File(javaHomeSys); if (!javaHome.exists()) { return null; } if (new java.io.File(javaHome, toolsJar).exists()) { return javaHome; } return null; } /** * Creates FileFilter that helps filter system. * Ant may add two tools.jar in classpath. It uses two JavaHome locations. One from java system property and one from OS environment * variable. Ant sources: org.apache.tools.ant.launch.Locator.getToolsJar. */ public static FileFilter newSystemFileFilter() { final java.io.File antHome = AntUtils.getAntHome(); final java.io.File javaHome = getJavaHome(); final java.io.File javaHome2 = getJavaHome2(); final Path antHomePath = antHome == null ? null : antHome.toPath(); final Path javaHomePath = javaHome == null ? null : javaHome.toPath(); final Path javaHomePath2 = javaHome2 == null ? null : javaHome2.toPath(); return new FileFilter() { @Override public boolean accept(java.io.File file) { final Path path = file.toPath(); // Skip ant and system jars return !(javaHomePath != null && path.startsWith(javaHomePath) || javaHomePath2 != null && path.startsWith(javaHomePath2) || antHomePath != null && path.startsWith(antHomePath)); } }; } public static Map<String, String> getAntEnvironmentInformation() throws IOException { final Map<String, String> versionInfo = new HashMap<>(); final LineConsumer cmdOutput = new LineConsumer() { boolean end = false; @Override public void writeLine(String line) throws IOException { if (line.isEmpty()) { end = true; } if (end) { return; } String key = null; int keyEnd = 0; int valueStart = 0; final int l = line.length(); while (keyEnd < l) { if (line.charAt(keyEnd) == ':') { valueStart = keyEnd + 1; break; } keyEnd++; } if (keyEnd > 0) { key = line.substring(0, keyEnd); } if (key != null) { while (valueStart < l && Character.isWhitespace(line.charAt(valueStart))) { valueStart++; } if ("Ant version".equals(key)) { int valueEnd = line.indexOf("compiled on", valueStart); final String value = line.substring(valueStart, valueEnd).trim(); versionInfo.put(key, value); } else { final String value = line.substring(valueStart); versionInfo.put(key, value); } } } @Override public void close() throws IOException { } }; readAntEnvironmentInformation(cmdOutput); return versionInfo; } private static void readAntEnvironmentInformation(LineConsumer cmdOutput) throws IOException { if (!Files.isReadable(BUILD_FILE_PATH)) { try (Writer writer = Files.newBufferedWriter(BUILD_FILE_PATH, Charset.forName("UTF-8"))) { writer.write(BUILD_FILE_CONTENT); } } final CommandLine commandLine = new CommandLine(getAntExecCommand()).add("-f", BUILD_FILE_PATH.toString(), "-quiet", "-emacs"); final ProcessBuilder processBuilder = new ProcessBuilder().command(commandLine.toShellCommand()).redirectErrorStream(true); final Process process = processBuilder.start(); ProcessUtil.process(process, cmdOutput, LineConsumer.DEV_NULL); } /** Get source directories. */ public static List<String> getSourceDirectories(java.io.File buildFile) throws IOException { return getSourceDirectories(readProject(buildFile)); } /** Get source directories. */ public static List<String> getSourceDirectories(VirtualFile buildFile) throws IOException { //TODO: try fix problem with some build.xml that don't have basedir prop return getSourceDirectories(readProject(buildFile)); } /** * Read description of ant project. * * @param buildFile * path to build.xml file * @return description of ant project */ public static Project readProject(java.io.File buildFile) throws IOException { org.apache.tools.ant.Project antProject = new org.apache.tools.ant.Project(); antProject.setBasedir(buildFile.getParentFile().getAbsolutePath()); //TODO: try fix problem with some build.xml that don't have basedir prop try { ProjectHelper2.configureProject(antProject, buildFile); } catch (Exception e) { // throw new IOException("Error parsing ant file. " + e.getMessage()); return antProject; //TODO: return empty project. Skip all parsing error. Lets importing project if not parse build.xml. In this case will used default props. } return antProject; } public static Project readProject(VirtualFile buildFile) throws IOException { return readProject(((VirtualFileImpl)buildFile).getIoFile()); } /** Get source directories. */ public static List<String> getSourceDirectories(Project project) { Hashtable<String, Object> properties = project.getProperties(); String absProjectPath = project.getBaseDir().getAbsolutePath(); List<String> paths = new ArrayList<>(2); if (properties.containsKey("src.dir")) { String srcPath = (String)properties.get("src.dir"); srcPath = srcPath.substring(absProjectPath.length()); if (srcPath.startsWith("/")) { srcPath = srcPath.substring(1); } paths.add(srcPath); } if (properties.containsKey("test.dir")) { String testPath = (String)properties.get("test.dir"); testPath = testPath.substring(absProjectPath.length()); if (testPath.startsWith("/")) { testPath = testPath.substring(1); } paths.add(testPath); } if (paths.isEmpty()) { paths.add("src"); paths.add("test"); } return paths; } }